function createContext(defaultValue, calculateChangedBits) {
	/*  
        context 对象本质 
        通过挂载 context 的 _currentValue 属性传递 context value
        
        如果有多个 Provider 的情况，那么后一个 contextValue 会覆盖
        前一个 contextValue。Provider 是用来传递 value ，而非保存 value

    
    */
	const context = {
		$$typeof: 'REACT_CONTEXT_TYPE', // 本质上就是 Consumer element 类型
		_calculateChangedBits: calculateChangedBits,
		_currentValue: defaultValue,
		_threadCount: 0,
		Provider: null,
		Consumer: null,
	}

	/* 本质上就是 Provider element 类型 */
	context.Provider = {
		$$typeof: 'REACT_PROVIDER_TYPE',
		_context: context,
	}
}
/* 调和阶段 ContextProvider 特有的fiber更新方法 */
function updateContextProvider(current, workInProgress, renderExpirationTime) {
	/* 获取 Provider 上的 value */
	pushProvider(workInProgress, newProps.value)
	/* 更新 context */
	if (oldProps !== null) {
		const changeBits = calculateChangedBits(
			context,
			newProps.value,
			oldProps.value
		)
		if (changeBits === 0) {
			/* context 没有变化 如果孩子们都一样的话 那么不需要更新 */
			if (
				oldProps.children === newProps.children &&
				!hasLegacyContextChanged()
			) {
				// return ... // 停止调和子节点，收尾工作
			} else {
				// 更新 context
				propagateContextChange(
					workInProgress,
					context,
					changeBits,
					renderExpirationTime
				)
			}
		}
	}
}
/* 
  深度遍历所有的子代 fiber 然后找到里面 具有 dependencies 的属性
*/
function propagateContextChange(
	workInProgress,
	context,
	changeBits,
	renderExpirationTime
) {
	let fiber = workInProgress.children
	if (fiber !== null) {
		fiber.return = workInProgress
	}
	while (fiber !== null) {
		/* 
            dependencies：保存的是 context 的依赖项
            什么时候会使用 context：
            1.有 contextType 静态属性指向的类组件
            2.使用 useContext hooks 的函数组件
            3.context 提供的 Consumer          
        */
		const list = fiber.dependencies
		while (list !== null) {
			if (list.context === context) {
				if (fiber.tag === ClassComponent) {
					/* 
                        会走 forceUpdate 逻辑
                        在类组件中，通过调用 this.forceUpdate() 带来的更新会被打上 ForceUpdate 类型的 tag
                        这里可以理解为强制更新 ，强制更新会跳过  PureComponent 和 shouldComponentUpdate 等优化策略 
                    */
					const update = createUpdate(renderExpirationTime, null)
					update.tag = ForceUpdate
					enqueueUpdate(fiber, update)
				}
				/* 
                    重要：TODO: 提高 fiber 的优先级，让当前 fiber 可以 beginWork ，并且向上更新父级 fiber 链上的优先级
                    1:类组件执行 render , 函数组件执行就是渲染吗？
                    在 React 整个 Reconciler 调和流程中，从更新调度任务的发起，再到 commit 和 render 两大
                    阶段， 再到真实 dom 的渲染，每一个环节都属于渲染的一部分 ，而开发者能够控制的 render 只是其中
                    的一小部分 - 类组件执行 render ，函数组件的执行。但是整个 fiber 树在调和阶段都需要更新，更新
                    调和 fiber 的方法在 react 底层叫做 beginWork 

                    beginWork:在一次更新中，只需要更新的 fiber 或者受牵连的 fiber 都会执行 beginWork
                    render:在一次更新中，只有类组件类型的 fiber 会执行render 得到新的 children。如果
                    组件触发 render 那么它一定经历过 beginWork
                     
                    如果一个组件发生更新，那么当前组件到fiber root 上的父级链上的所有的fiber，更新优先级都会提高
                    都会触发 beginWork

                    一次 beginWork ，一个 fiber 下的同级兄弟 fiber 会发生对比，找到任务优先级高的 fiber ，向下
                    beginWork

                    2:Context 改变如何做到消费 context 的组件（更新原理）
                    Provider 更新，会递归所有的子组件，只要消费了 context 的子fiber 都会给一个高优先级
                    而且向上更新父级 fiber 链上的优先级，让所有父级fiber 都处于一个高优先级，那么接下来高优先级
                    的 fiber 都会 beginWork
                */
			}
		}
	}
}
/* 
    在调和阶段，会转化成ContextConumer 类型的对象 
    在 beginWork 中，会调用 updateContextConsumer
*/
function updateContextConsumer(current, workInProgress, renderExpirationTime) {
	let context = workInProgress.type
	const newProps = workInProgress.dependencies
	/* 得到 render props children */
	const render = newProps.children
	/* 读取 context  */
	prepareToReadContext(workInProgress, renderExpirationTime)
	/* 得到最新的 context value */
	const newValue = readContext(context, newProps.unstable_observedBits)
	let newChildren
	/* 得到最新的 children element */
	newChildren = render(newValue)
	workInProgress.effectTag |= PerformedWork
	/* 调和 children */
	reconcileChildren(
		current,
		workInProgress,
		newChildren,
		renderExpirationTime
	)
	return workInProgress.children
}
/*
    useContext => readContext (本质就是readContext)
    函数组件通过 readContext ，将函数组件的 dependencies 和
    当前 context 建立起关联，context 改变，将当前函数组件设计高
    优先级，使其渲染

    类组件的静态属性 contextType 和 useContext 一样

*/
function readContext(context, observedBits) {
	const contextItem = {
		context,
		observedBits,
		next: null,
	}
	/* 不存在最后一个 context Dependency */
	if (lastContextDependency === null) {
		lastContextDependency = contextItem
		currentlyRenderingFiber.dependencies = {
			expirationTime: NoWork,
			firstContext: contextItem,
			responders: null,
		}
	} else {
		/* 存在的情况 */
		lastContextDependency = lastContextDependency.next = contextItem
	}

	return isPrimaryRenderer ? context._currentValue : context._currentValue2
}
/* 
    静态属性 contextType，在类组件实例话的时候被调用
    本质上也是调用 readContext 将 context 和 fiber
    上的 dependencies 建立起关联

*/
function constructClassInstance(workInProgress, ctor, props) {
	if (typeof contextType === 'object' && contextType !== null) {
		/* 读取 contextType */
		context = readContext(createContext)
	}

	const instance = new ctor(props, context)
}

/* React 18 新特性 useMutableSource  */
/* 

    beginWork 和 render 全流程 
    
    fiber 是调和过程中的最小单元，每一个需要调和的 fiber 都会进入 workLook
    而组件是最小的更新单元，React 的更新源于数据层 state 的变化

    lane: 更新优先级（在一次更新任务，将赋予给更新的fiber一个
    更新优先级lane）
    childLanes:children 中更新优先级。（如果当前 fiber 的child中
    有高优先级任务，那么当前fiber的 childLanes 等于当前优先级）
*/
function scheduleUpdateOnFiber(fiber, lane) {
	/* 递归向上标记更新优先级 */
	const root = markUpdateLaneFromFiberToRoot(fiber, lane)
	if (root === null) return null
	/* 
        如果当前 root 确定更新，那么会执行 ensureRootIsScheduled 
        根据任务的类型，发起异步调度任务，然后走调度流程
        对于 legacy sync 模式最后的更新任务是 performSyncWorkOnRoot
        对于 Concurrent 模式最后的更新任务是 performConcurrentWorkOnRoot
    */
	ensureRootIsScheduled(root, eventTime)
}
/**
 *
 * @param {*} sourceFiber 产生 state 变化的 fiber，比如组件 A 触发了 useState, 那么组件 A对应的
 * @param {*} lane        产生的更新优先级
 */
function markUpdateLaneFromFiberToRoot(sourceFiber, lane) {
	/* 更新当前 fiber 上 */
	sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane)
	/* 更新缓存树上的 lanes */
	let alternate = sourceFiber.alternate
	if (alternate !== null) alternate.lanes = mergeLanes(alternate.lanes, lane)
	/* 当前更新的 fiber */
	let node = sourceFiber
	/* 找到返回父级 */
	let parent = sourceFiber.return
	while (parent !== null) {
		/* TODO: 更新 childLanes 字段 */
		parent.childLanes = mergeLanes(parent.childLanes, lane)
		if (alternate !== null) {
			alternate.childLanes = mergeLanes(alternate.childLanes, lane)
		}
		/* 递归遍历 */
		node = parent
		parent = parent.return
	}
}
/* 
    既然要从头更新，又不想调和整个 fiber 树，那么如何找到更新的
    组件A,这个时候 childLanes 就派上用场了，如果 A 发生了更新
    那么先向上递归更新父级链的 childLanes，接下来从 rootFiber
    向下调和的时候，发现 childLanes 等于当前优先级，那么说明它的
    child 链上有更细任务,则会继续向下调和，反之退出调和流程
*/
/* 
    正式进入了 fiber 的调和流程
*/
function performSyncWorkOnRoot(root) {
	/* render 阶段 */
	let exitStatus = renderRootSync(root, lanes)
	/* commit 阶段 将 fiber tree转化为真实dom */
	commitRoot(root)
	/* 如果有其他的等待中的任务，那么继续更新 */
	ensureRootIsScheduled(root, now())
}
function ensureRootIsScheduled(root, currentTime) {
	var existingCallbackNode = root.callbackNode

	/* 计算一下执行更新的优先级 */
	var newCallbackPriority = getHighestPriorityLane(nextLanes)
	/* 当前 root 上存在的更新优先级 */
	const existingCallbackPriority = root.callbackPriority
	/* 
        如果两者相等，那么说明是在同一次更新中
        如果在正常模式下（非异步）一次更新中触发了多次 setState 或者 useState ，
        那么第一个 setState 进入到 ensureRootIsScheduled 就会有 root.callbackPriority = newCallbackPriority
        将不会进入到调度任务，这才是批量跟新的原理，多次更新只有第一次会进入到调度中
    */
	if (
		newCallbackPriority === existingCallbackPriority &&
		!(
			ReactCurrentActQueue.current !== null &&
			existingCallbackNode !== fakeActCallbackNode
		)
	)
		/* 批量更新 */
		return
	/* 同步更新条件下，会走这条逻辑 */
	if (newCallbackPriority === SyncLane) {
		scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root))
		/*  
            用微任务立即去更新
            在老版本的 React 是基于事件处理函数执行的  flushSyncCallbacks
            而新版本是通过 scheduleMicrotask
        */
		scheduleMicrotask(flushSyncCallbacks)
	} else {
		/* 
            异步条件
            setTimeout/Promise.resolve
        */
		newCallbackNode = scheduleCallbck(
			schedulerPriorityLevel,
			performSyncWorkOnRoot.bind(null, root)
		)
	}
	/* ⚠️：给当前 root 的更新优先级，绑定到最新的优先级 */
	root.callbackPriority = newCallbackPriority
	root.callbackNode = newCallbackNode
}
function scheduleSyncCallback(callback) {
	if (syncQueue === null) {
		/* 如果队列为空 */
		syncQueue = [callback]
		/* 
            进入调度任务
            flushSyncCallbackQueueImpl 会真正的执行 callback:本质上就是调和函数 performSyncWorkOnRoot
            Scheduler_scheduleCallback：调度的执行方法 本质上就是通过 MessageChannel 想浏览器请求下一空闲帧
            在空闲帧中执行更新任务
        */
		immediateQueueCallbackNode = Scheduler_scheduleCallback(
			Scheduler_ImmediatePriority,
			flushSyncCallbackQueueImpl
		)
	} else {
		/* 将任务放入到队列中 */
		syncQueue.push(callback)
	}
}
function scheduleCallbck(priorityLevel, callback) {
	var actQueue = ReactCurrentActQueue.current
	if (actQueue !== null) {
		actQueue.push(callback)
		return fakeActCallbackNode
	}
	return scheduleCallbck(priorityLevel, callback)
}
var scheduleMicrotask =
	typeof queueMicrotask === 'function'
		? queueMicrotask
		: typeof Promise !== 'undefined'
		? function (callback) {
				return Promise.resolve(null)
					.then(callback)
					.catch(handleErrorInNextTick)
		  }
		: scheduleTimeout
/* 
    问题：比如浏览器空闲状态下发生一次 state 更新，那么最后一定会进入调度，等到
    下一次空闲帧执行吗？
    答：否定的，如果是这样，那么就是一种性能上的浪费，因为正常情况下，发生更新希望的是
    一次事件循环中执行完更新到视图渲染，如果在下一次事件循环中执行，那么更新肯定会延时

    空闲时期的同步任务
    在没有更新任务空闲期的条件下，为了让更新变成同步，也就是本次更新不在调度中执行，那么
    React 对于更新，会用 flushSyncCallbackQueue 立即执行更新队列，发起更新任务，目的
    就是让任务不延时到下一帧，但是此时调度会正常执行，不过调度中的任务已被清空
*/
function batchEventUpdates(fn, a) {
	/* 批量更新流程，没有更新状态下，那么直接执行任务 */
	var prevExecutionContext = executionContext
	executionContext |= EventContext
	try {
		return fn(
			a
		) /* 执行事件本身，React 事件在这里执行，useState/setState 也会在这里执行 */
	} finally {
		/* 重置状态 */
		executionContext = prevExecutionContext
		/* 
            非可控的更新任务，setTimeout/Promise 里面的更新 打破批量更新的原则
            本质上是因为，执行一次 useState/setState 就会触发 flushSyncCallbackQueue 
            立即触发，就会进入调和阶段，去真正的更新 fiber 树
        */
		if (executionContext === NoContext) {
			/* 批量更新流程，没有更新状态下，那么直接执行任务 */
			flushSyncCallbackQueue()
		}
	}
}
function renderRootSync(root, lanes) {
	workLoopSync()
	/* workLoop 完毕后，证明所有节点都遍历完毕，那么重置状态，进入 commit 阶段 */
	workInProgressRoot = null
	workInProgressRootRenderLanes = null
}
/* 循环执行 preformUnitOfWork ，一指到 workInProgress 为空 */
function workLoopSync() {
	/* 
        shouldYield 判断有没有过期的任务，有过期的任务，会中断
         workLoop，那么也就说明 render 阶段时可以被打断的
    */
	while (workInProgress !== null && !shouldYield) {
		preformUnitOfWork(workInProgress)
	}
}

function preformUnitOfWork(uniOfWork) {
	const current = uniOfWork.alternate
	// beginWork 向下调和流程
	let next = beginWork(current, uniOfWork, subtreeRenderLanes)
	uniOfWork.memoizedProps = uniOfWork.pendingProps
	if (next === null) {
		// 向上归并
		completeUnitOfWork(uniOfWork)
	} else {
		workInProgress = next
	}
}
/**
 *
 * @param {*} current fiber
 * @param {*} workInProgress fiber
 * @param {*} renderLanes 当前 render 优先级
 */
function beginWork(current, workInProgress, renderLanes) {
	/* 
        第一部分
        主要针对更新，如果是初始化，那么直接跳过第一阶段
        mounted => current = null
    */
	if (current !== null) {
		/* 更新流程 */
		/* current 树上一次渲染后的 props */
		const oldProps = current.memoizedProps
		/* 
            workInProgress 树这一次更新的 props
            didReceiveUpdate:这个变量主要证明当前更新是否来源于父级的更新，那么自身并没有更新
            比如 更新组件 B，那么 C 也会更着更新，这个情况下 didReceiveUpdate = true
        */
		const newProps = workInProgress.pendingProps
		if (oldProps !== newProps || hasLegacyContextChanged()) {
			didReceiveUpdate = true
		} else {
			/* 
                props 和 context 没有发生变化，检查是否更新来自或者 context 改变

                props 相等有3种情况
                1：子组件更新，父组件被标记 ChildLanes ，会进入到 beginWork 调和阶段，
                但是父组件本身 props 不会发生变化
                2：通过 useMemo 等方式缓存了 React element 元素
                3：就是更新当前组件，但是 props 并未发生变化
            */

			/* 情况3 */
			const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(
				current,
				renderLanes
			)
			/* 情况1 */
			if (!hasScheduledUpdateOrContext) {
				didReceiveUpdate = false
				return attemptEarlyBailoutIfNoScheduledUpdate(
					current,
					workInProgress,
					renderLanes
				)
			}
			// ...
			didReceiveUpdate = false
		}
	} else {
		didReceiveUpdate = false
	}
	/* 第二部分 */
	/* TODO:走到这里流程会被调和｜更新，比如函数执行被执行，类组件会执行 render  */

	switch (workInProgress.tag) {
		/* 函数组件 */
		case FunctionComponent: {
			return updateFunctionComponent(
				current,
				workInProgress,
				Component,
				resolvedProps,
				renderLanes
			)
		}
		/* 类组件 */
		case ClassComponent: {
			return updateClassComponent(
				current,
				workInProgress,
				Component,
				resolvedProps,
				renderLanes
			)
		}
		/* 元素类型 fiber div / span */
		case HostComponent: {
			return updateHostComponent(current, workInProgress, Component)
		}
	}
}
function checkScheduledUpdateOrContext(current, renderLanes) {
	const updateLanes = current.lanes
	/* 这种情况说明当前要更新 */
	if (includesSomeLane(updateLanes, renderLanes)) {
		return true
	}
	/* 如果该 fiber 消费了 context ，并且 context 发生了变化 */
	if (enableLazyContextPropagation) {
		const dependencies = current.dependencies
		if (dependencies !== null && checkIfContextChanged(dependencies)) {
			return true
		}
	}
	return false
}
/* 
    attemptEarlyBailoutIfNoScheduledUpdate 会处理部分 context 逻辑 
    调用了 bailoutOnAlreadyFinishedWork
*/
function bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes) {
	/* 
        如果 children 没有高优先级的任务，说明所有的 child 都没有更新，那么
        直接返回，child 也不会被调和
    */
	if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {
		/* 简化 */
		return null
	}
	/* 当前 fiber 没有更新，但是它的 children 需要更新 */
	cloneChildFibers(current, workInProgress)
	return workInProgress.child
}
